package logservice

import (
	"errors"
	"fmt"
	"time"
	"yunj/pkg/yunj/app/dto"
	"yunj/pkg/yunj/app/model"
	"yunj/pkg/yunj/app/service/admin/adminservice"
	"yunj/pkg/yunj/config"
	"yunj/pkg/yunj/core/builder"
	"yunj/pkg/yunj/core/builder/builderdto"
	"yunj/pkg/yunj/core/builder/form"
	"yunj/pkg/yunj/core/builder/form/field"
	"yunj/pkg/yunj/core/builder/table"
	"yunj/pkg/yunj/core/builder/table/col"
	"yunj/pkg/yunj/core/builder/table/deftoolbar"
	"yunj/pkg/yunj/core/consts"
	"yunj/pkg/yunj/core/db"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type logPage struct {
}

var LogPage *logPage

// 列表构建器
func (s *logPage) ListBuilder(ctx *gin.Context, queryHandler func(query *gorm.DB) (err error)) *builder.Table {
	return builder.NewTable(ctx, "LogList").
		Filter(func(t *builder.Table, state *builderdto.TableState) (fields []form.FieldInterface, err error) {
			ipProvinceOptions := []builderdto.Option{
				{Label: "所有", Value: consts.ALL_SELECT_VALUE},
			}
			for _, province := range config.Provinces {
				ipProvinceOptions = append(ipProvinceOptions, builderdto.Option{
					Label: province,
					Value: province,
				})
			}
			ipProvinceOptions = append(ipProvinceOptions, builderdto.Option{
				Label: "其他",
				Value: consts.OTHER_SELECT_VALUE,
			})
			fields = []form.FieldInterface{
				field.NewDate("timeRange", "时间范围").SetRange("到").SetVerify("required").SetMax(time.Now().Format("2006-01-02")).SetDefault(map[string]any{
					"start": time.Now().Format("2006-01") + "-01",
					"end":   time.Now().Format("2006-01-02"),
				}),
				field.NewDropdownSearch("memberIds", "管理员").SetOptionsApi(util.BuildAdminUrl("/member/dropdownSearchOptions")).SetMulti(true),
				field.NewText("dataId", "数据ID"),
				field.NewSelect("ipProvince", "IP所在地").SetOptions(ipProvinceOptions).SetDefault(consts.ALL_SELECT_VALUE),
			}
			return
		}).
		DefaultToolbar([]deftoolbar.ActionInterface{
			deftoolbar.NewFilter(),
			deftoolbar.NewExport(),
		}).
		Cols(func(t *builder.Table, state *builderdto.TableState) (cols []table.ColInterface, err error) {
			cols = []table.ColInterface{
				col.NewDatetime("created_at", "时间"),
				col.NewText("url_info", "URL"),
				col.NewText("desc", "描述"),
				col.NewText("member_name", "管理员"),
				col.NewText("data_id", "数据ID"),
				col.NewJson("request_params", "请求参数"),
				col.NewJson("response_content", "响应内容"),
				col.NewText("ip_info", "IP"),
				col.NewText("device_info", "设备信息"),
				col.NewText("latency_desc", "耗时"),
			}
			return
		}).
		Count(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableCountResult, err error) {
			var filterFormParam dto.AdminMemberLogPageListFilterFormParam
			util.MapToStruct(requestParam.FilterData(), &filterFormParam)
			query, err := s.listBuilderQuery(ctx, requestParam, &filterFormParam, queryHandler)
			if err != nil {
				return
			}
			if err = query.Count(&res.Count).Error; err != nil {
				err = fmt.Errorf("数量查询异常！%v", err)
			}
			return
		}).
		Items(func(t *builder.Table, requestParam *builderdto.TableRequestParam) (res builderdto.TableItemsResult, err error) {
			var filterFormParam dto.AdminMemberLogPageListFilterFormParam
			util.MapToStruct(requestParam.FilterData(), &filterFormParam)
			query, err := s.listBuilderQuery(ctx, requestParam, &filterFormParam, queryHandler)
			if err != nil {
				return
			}
			var logItems []*model.AdminMemberLog
			if err = query.Preload("Member").Order("created_at desc").Limit(requestParam.Limit()).Offset(requestParam.Offset()).Find(&logItems).Error; err != nil {
				err = fmt.Errorf("数据查询异常！%v", err)
				return
			}
			res.Items, err = s.listBuilderItemsHandle(logItems)
			return
		})
}

func (s *logPage) listBuilderQuery(ctx *gin.Context, requestParam *builderdto.TableRequestParam, filterFormParam *dto.AdminMemberLogPageListFilterFormParam, queryHandler func(query *gorm.DB) (err error)) (query *gorm.DB, err error) {
	startMonthTime, _ := time.ParseInLocation("2006-01-02", filterFormParam.TimeRange.Start, time.Local)
	endMonthTime, _ := time.ParseInLocation("2006-01-02", filterFormParam.TimeRange.End, time.Local)
	suffixs := []string{}
	i := 1
	for {
		if startMonthTime.Unix() > endMonthTime.Unix() {
			break
		}
		if i > 12 {
			err = errors.New("查询开始时间到截至时间，间隔不能超过12个月")
			return
		}
		suffixs = append(suffixs, startMonthTime.Format("_200601"))
		startMonthTime = startMonthTime.AddDate(0, 1, 0)
		i++
	}
	// 单表查询
	if len(suffixs) == 1 {
		query = db.Model(&model.AdminMemberLog{}).SetTableNameSuffix(suffixs[0]).GormDB()
		// 处理条件
		err = s.listBuilderQueryHandle(ctx, query, requestParam, filterFormParam, queryHandler)
		return
	}
	// 多表查询
	query, err = db.Model(&model.AdminMemberLog{}).SetUnionAllTableNameSuffixs(suffixs, func(suffix string, subquery *gorm.DB) (err error) {
		// 处理条件
		err = s.listBuilderQueryHandle(ctx, subquery, requestParam, filterFormParam, queryHandler)
		return
	}).UnionAllGormDB()
	return
}

// 列表查询对象处理
func (s *logPage) listBuilderQueryHandle(ctx *gin.Context, query *gorm.DB, requestParam *builderdto.TableRequestParam, filterFormParam *dto.AdminMemberLogPageListFilterFormParam, queryHandler func(query *gorm.DB) (err error)) (err error) {
	// 查询字段
	if requestParam.IsCountRequest() {
		query.Select("id") // 数量查询，只选主键，减少查询字段
	} else {
		query.Select("id", "auth_key", "url", "method", "member_id", "data_id", "ip", "ip_province", "platform", "platform_version", "browser", "browser_version", "created_at", "latency")
	}
	// 查询条件
	// 查询成员范围
	currMember := adminservice.GetLoginMember(ctx)
	if !currMember.IsHasAllAuth() {
		var viewAndOperateMemberIds []uint64
		viewAndOperateMemberIds, err = currMember.GetViewAndOperateMemberIds()
		if err != nil {
			return
		}
		query.Where("member_id in ?", viewAndOperateMemberIds)
	}
	// keys
	if len(requestParam.Pks) > 0 {
		query.Where("id in ?", requestParam.Pks)
	}
	// timeRange
	query.Where("created_at >= ? and created_at <= ?", filterFormParam.TimeRange.Start+" 00:00:00", filterFormParam.TimeRange.End+" 23:59:59")
	// memberIds
	if len(filterFormParam.MemberIds) > 0 {
		query.Where("member_id in ?", filterFormParam.MemberIds)
	}
	// dataId
	if filterFormParam.DataId != "" {
		query.Where("data_id = ?", filterFormParam.DataId)
	}
	// ipProvince
	if filterFormParam.IpProvince != "" && filterFormParam.IpProvince != consts.ALL_SELECT_VALUE {
		if filterFormParam.IpProvince == consts.OTHER_SELECT_VALUE {
			query.Where("ip_province = ''")
		} else {
			query.Where("ip_province = ?", filterFormParam.IpProvince)
		}
	}
	// queryHandler
	if queryHandler != nil {
		err = queryHandler(query)
	}
	return
}

// 列表数据项处理
func (s *logPage) listBuilderItemsHandle(items []*model.AdminMemberLog) (resItems []*dto.AdminMemberLogPageListItemResponse, err error) {
	if len(items) <= 0 {
		return
	}
	// 获取日志属性数据
	var logMinTime time.Time
	var logMaxTime time.Time
	logIds := make([]uint64, 0, len(items))
	for _, item := range items {
		logIds = append(logIds, item.Id)
		if logMinTime.IsZero() {
			logMinTime = *item.CreatedAt
		} else {
			if logMinTime.Unix() > item.CreatedAt.Unix() {
				logMinTime = *item.CreatedAt
			}
		}
		if logMaxTime.IsZero() {
			logMaxTime = *item.CreatedAt
		} else {
			if logMaxTime.Unix() < item.CreatedAt.Unix() {
				logMaxTime = *item.CreatedAt
			}
		}
	}
	logAttrMap, err := s.listBuilderLogAttrMap(logIds, logMinTime, logMaxTime)
	if err != nil {
		return
	}
	// isRequestExportItems := t.IsRequestExportItems() // 是否请求导出items
	resItems = make([]*dto.AdminMemberLogPageListItemResponse, 0, len(items))
	for _, item := range items {
		resItem := &dto.AdminMemberLogPageListItemResponse{
			Id:          item.Id,
			CreatedAt:   item.CreatedAt.Format("2006-01-02 15:04:05"),
			UrlInfo:     fmt.Sprintf("%s %s", item.Method, item.Url),
			DataId:      item.DataId,
			LatencyDesc: util.LatencyDescByMs(item.Latency),
		}
		// member_name
		if item.Member != nil {
			resItem.MemberName = fmt.Sprintf("%s【%s】", item.Member.Name, item.Member.Username)
		}
		// ip_info
		ipInfo := ""
		if item.IpProvince != "" {
			ipInfo += item.IpProvince + " "
		}
		ipInfo += item.Ip
		resItem.IpInfo = ipInfo
		// device_info
		deviceInfo := ""
		if item.Platform != "" {
			deviceInfo += item.Platform
			if item.PlatformVersion != "" {
				deviceInfo += "(" + item.PlatformVersion + ")"
			}
		}
		if item.Browser != "" {
			deviceInfo += " " + item.Browser
			if item.BrowserVersion != "" {
				deviceInfo += "(" + item.BrowserVersion + ")"
			}
		}
		resItem.DeviceInfo = deviceInfo
		// attr
		if attr, exists := logAttrMap[item.Id]; exists {
			// desc
			resItem.Desc = attr.Desc
			// request_params
			resItem.RequestParams = attr.RequestParams
			// response_content
			resItem.ResponseContent = attr.ResponseContent
		}
		resItems = append(resItems, resItem)
	}
	return
}

func (s *logPage) listBuilderLogAttrMap(logIds []uint64, minTime time.Time, maxTime time.Time) (attrMap map[uint64]*model.AdminMemberLogAttr, err error) {
	suffixs := []string{}
	i := 1
	for {
		if minTime.Unix() > maxTime.Unix() {
			break
		}
		suffixs = append(suffixs, minTime.Format("_200601"))
		minTime = minTime.AddDate(0, 1, 0)
		i++
	}
	var attrs []*model.AdminMemberLogAttr
	var query *gorm.DB
	attrMap = map[uint64]*model.AdminMemberLogAttr{}
	if len(suffixs) == 1 {
		// 单表查询
		query = db.Model(&model.AdminMemberLogAttr{}).SetTableNameSuffix(suffixs[0]).GormDB()
		if err = query.Select("log_id", "request_params", "response_content", "desc").Where("log_id in ?", logIds).Find(&attrs).Error; err != nil {
			err = fmt.Errorf("日志属性数据查询异常！%v", err)
			return
		}
	} else {
		// 多表查询
		query, err = db.Model(&model.AdminMemberLogAttr{}).SetUnionAllTableNameSuffixs(suffixs, func(suffix string, subquery *gorm.DB) (err error) {
			subquery.Select("log_id", "request_params", "response_content").Where("log_id in ?", logIds)
			return
		}).UnionAllGormDB()
		if err != nil {
			err = fmt.Errorf("日志多表属性数据查询对象获取异常！%v", err)
			return
		}
		if err = query.Find(&attrs).Error; err != nil {
			err = fmt.Errorf("日志多表属性数据查询异常！%v", err)
			return
		}
	}
	if len(attrs) == 0 {
		return
	}
	for _, attr := range attrs {
		attrMap[attr.LogId] = attr
	}
	return
}
